#include "env.h"
#include "log.h"
#include <string.h>
#include <iostream>
#include <iomanip>
#include <unistd.h>
#include <stdlib.h>
#include "config.h"

namespace johnsonli
{
    static johnsonli::Logger::ptr g_logger = LOG_NAME("system");

    bool Env::init(int argc, char** argv) 
    {
        char link[1024] = {0};
        char path[1024] = {0};
        sprintf(link, "/proc/%d/exe", getpid());
        readlink(link, path, sizeof(path));

        // /home/lizq/project/c++/test
        m_exe = path;

        auto pos = m_exe.find_last_of("/");
        // /home/lizq/project/c++
        m_cwd = m_exe.substr(0, pos) + "/";

        m_program = argv[0];

        if(argc > 1)
        {
            int i = 1;
            int j;
            for(j = 2; j < argc; ++j)
            {
                if(argv[i][0] == '-' && argv[j][0] == '-')
                {
                    add(argv[i]+1, "");
                    i = j;
                }
                else if(argv[i][0] == '-' && argv[j][0] != '-')
                {
                    add(argv[i]+1, argv[j]);         
                    j++;    // 下一个要解析的地方
                    i = j;  
                }
                else return false;
            }

            if(i < argc )   //还有最后1个的时候
            {
                if(argv[i][0] == '-') add(argv[i]+1, "");
                else return false;              
            }
          
        }
       
        return true;
    }

    void Env::add(const std::string& key, const std::string& val) 
    {
        RWMutexType::WriteLock lock(m_mutex);
        m_args[key] = val;
    }

    bool Env::has(const std::string& key) 
    {
        RWMutexType::ReadLock lock(m_mutex);
        auto it = m_args.find(key);
        return it != m_args.end();
    }

    void Env::del(const std::string& key) 
    {
        RWMutexType::WriteLock lock(m_mutex);
        m_args.erase(key);
    }

    std::string Env::get(const std::string& key, const std::string& default_value) 
    {
        RWMutexType::ReadLock lock(m_mutex);
        auto it = m_args.find(key);
        return it != m_args.end() ? it->second : default_value;
    }

    void Env::addHelp(const std::string& key, const std::string& desc) 
    {
        removeHelp(key);
        RWMutexType::WriteLock lock(m_mutex);
        m_helps.push_back(std::make_pair(key, desc));
    }

    void Env::removeHelp(const std::string& key) 
    {
        RWMutexType::WriteLock lock(m_mutex);
        for(auto it = m_helps.begin();
                it != m_helps.end();) 
        {
            if(it->first == key) 
            {
                it = m_helps.erase(it);
            } 
            else 
            {
                ++it;
            }
        }
    }

    void Env::printHelp() 
    {
        RWMutexType::ReadLock lock(m_mutex);
        std::cout << "Usage: " << m_program << " [options]" << std::endl;
        for(auto& i : m_helps) 
        {
            std::cout << std::setw(5) << "-" << i.first << " : " << i.second << std::endl;
        }
    }

    bool Env::setEnv(const std::string& key, const std::string& val) 
    {
        return !setenv(key.c_str(), val.c_str(), 1);
    }

    std::string Env::getEnv(const std::string& key, const std::string& default_value) 
    {
        const char* v = getenv(key.c_str());
        if(v == nullptr) 
        {
            return default_value;
        }
        return v;
    }

    std::string Env::getAbsolutePath(const std::string& path) const 
    {
        
        if(path.empty())
        {
            return "/";
        }
        if(path[0] == '/')
        {
            return path;
        }
        return m_cwd + path;
    }

    std::string Env::getAbsoluteWorkPath(const std::string& path) const {
        if(path.empty()) {
            return "/";
        }
        if(path[0] == '/') {
            return path;
        }
        static johnsonli::ConfigVar<std::string>::ptr g_server_work_path =
            johnsonli::Config::Lookup<std::string>("server.work_path");
        return g_server_work_path->getValue() + "/" + path;
    }

    std::string Env::getConfigPath() 
    {
        return getAbsolutePath(get("c", "config"));
    }
    
}
